package org.bigjava.novelplatform.common.utils;

import io.jsonwebtoken.*;
import org.bigjava.novelplatform.common.exception.ExceptionCodeMessage;
import org.bigjava.novelplatform.common.exception.UserActionException;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.lang.reflect.Field;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import static org.bigjava.novelplatform.common.constant.NovelInfoConstant.SIGNATURE;
import static org.bigjava.novelplatform.common.constant.NovelInfoConstant.TOKEN_EXPIRE_MILLIS;

/**
 * token工具类
 * 只用jwt校验用户状态，绝对不会用jwt中的数据作数据库查询
 * @author ykh
 * @create 2022-04-15 20:18
 */
public class TokenUtils {

    public static String createToken(Object obj){
        Field[] fields = obj.getClass().getDeclaredFields();
        HashMap<String, Object> map = new HashMap<>();
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                map.put(field.getName(),field.get(obj));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return createToken(map);
    }

    public static String createToken(Map<String, Object> claimMap){
        return createToken(claimMap,null);
    }

    public static String createToken(Map<String, Object> claimMap,Long tokeTimeOut){
        if(tokeTimeOut == null){
            tokeTimeOut = TOKEN_EXPIRE_MILLIS;
        }
        return Jwts.builder()
                //设置头（可选）
                .setHeaderParam("type", "JWT")
                .setHeaderParam("alg", "HS256")
                // 设置主题（声明信息）
                .setSubject("userInfo")
                //签发者
                .setIssuer("novel")
                //接收方
                .setAudience("novel_vue")
                //设置Payload
                .addClaims(claimMap)
                //设置签发时间
                .setIssuedAt(new Date(System.currentTimeMillis()))
                //设置生效时间
                .setNotBefore(new Date(System.currentTimeMillis()))
                //设置过期时间
                .setExpiration(new Date(System.currentTimeMillis() + tokeTimeOut))
                .setId(UUID.randomUUID().toString())
                // 设置安全密钥（生成签名所需的密钥和算法）
                .signWith(SignatureAlgorithm.HS256, SIGNATURE)
                // 生成token（1.编码 Header 和 Payload 2.生成签名 3.拼接字符串）
                .compact();
    }

    /**
     * 无效token返回false
     * @param token
     * @return
     */
    public static Boolean parentToken(String token){
        if (StringUtils.isEmpty(token)) {
            return false;
        }
        Jwts.parser();
        try {
            Jwts.parser().setSigningKey(SIGNATURE).parseClaimsJws(token);
        } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | SignatureException | IllegalArgumentException e) {
            return false;
        }
        return true;

    }

    /**
     * 必须保证token不能为null
     * @param token
     * @return
     */
    public static Claims parentTokenGetData(String token){
        Jwts.parser();
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(SIGNATURE).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        return claims;
    }

    public static class JwtUtil{
        private static final long tokenExpiration = TOKEN_EXPIRE_MILLIS;
        private static final String tokenSignKey = SIGNATURE;

        private static Key getKeyInstance(){
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
            byte[] bytes = DatatypeConverter.parseBase64Binary(tokenSignKey);
            return new SecretKeySpec(bytes,signatureAlgorithm.getJcaName());
        }

        public static String createToken(Integer userId, String userName) {
            String token = Jwts.builder()
                    .setSubject("SRB-USER")
                    .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                    .claim("userId", userId)
                    .claim("userName", userName)
                    .signWith(SignatureAlgorithm.HS512, getKeyInstance())
                    .compressWith(CompressionCodecs.GZIP)
                    .compact();
            return token;
        }

        /**
         * 判断token是否有效
         * @param token
         * @return
         */
        public static boolean checkToken(String token) {
            if(StringUtils.isEmpty(token)) {
                return false;
            }
            try {
                Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);
                return true;
            } catch (Exception e) {
                return false;
            }
        }


        public static Integer getUserId(String token) {
            Claims claims = getClaims(token);
            Integer userId = (Integer)claims.get("userId");
            return userId;
        }

        public static String getUserName(String token) {
            Claims claims = getClaims(token);
            return (String)claims.get("userName");
        }

        public static void removeToken(String token) {
            //jwttoken无需删除，客户端扔掉即可。
        }

        /**
         * 校验token并返回Claims
         * @param token
         * @return
         */
        private static Claims getClaims(String token) {
            if(StringUtils.isEmpty(token)) {// 未登录
                throw new UserActionException(ExceptionCodeMessage.UN_LOGIN);
            }
            try {
                Jws<Claims> claimsJws = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);
                Claims claims = claimsJws.getBody();
                return claims;
            } catch (Exception e) {
            throw new UserActionException(ExceptionCodeMessage.UN_LOGIN);
            }
        }
    }




}
